﻿using System;
using System.IO;
using System.Linq;
using Expect.Core.Config;
using System.Collections.Generic;

namespace Expect.Report.Word
{    
    public class ReportConfiguration
    {
        public const string launchhelp = ", launch command with -help to get help";

        public string SpecificationsStyle { get; set; }
        
        public string DescriptionsStyle { get; set; }
        
        public string[] HeadingStyles { get; set; }

        public string TablesStyle { get; set; }

        public string Source { get; set; }

        public string Output { get; set; }

        public string TemplateFile { get; set; }

        public bool Verbose { get; set; }

        private List<TextBloc> _blocs = new List<TextBloc>();

        public List<TextBloc> Blocs
        {
            get
            {
                return this._blocs;
            }
            set
            {
                this._blocs = value;
            }
        }

        private List<TextRun> _runs = new List<TextRun>();

        public List<TextRun> Runs
        {
            get
            {
                return this._runs;
            }
            set
            {
                this._runs = value;
            }
        }

        public Dictionary<string, string> CustomProperties { get; set; }

        private ParametersConfiguration parameters = new ParametersConfiguration();

        public ParametersConfiguration Parameters
        {
            get
            {
                return this.parameters;
            }
            set
            {
                this.parameters = value;
            }
        }

        public static ReportConfiguration ReadFrom(string[] arguments)
        {
            ReportConfiguration cfg = new ReportConfiguration();
            cfg.Source = ReadArgument(arguments, "source");
           
            cfg.Output = ReadArgument(arguments, "output");
            cfg.TemplateFile = ReadArgument(arguments, "template");
            cfg.DescriptionsStyle = ReadArgument(arguments, "descriptions");
            cfg.HeadingStyles = ReadArgumentList(arguments, "headings");
            cfg.TablesStyle = ReadArgument(arguments, "tables");
            cfg.TablesStyle = ReadArgument(arguments, "specifications");
            cfg.Verbose = ReadArgument(arguments, "verbose") == "1";
            cfg.CustomProperties = ReadCustomProperties(arguments);

            if (!string.IsNullOrEmpty(cfg.Source) && File.Exists(cfg.Source + ".config"))
            {
                using (StreamReader reader = new StreamReader(cfg.Source + ".config"))
                {
                    string configcontent = reader.ReadToEnd();
                    var expectCfg = ExpectConfigurationSection.ReadFromContent(configcontent);
                    if (expectCfg != null && expectCfg.Report.Verbose == "1" && !cfg.Verbose)
                    {
                        cfg.Verbose = true;
                    }

                    if (expectCfg != null && !string.IsNullOrEmpty(expectCfg.Report.TemplateFile))
                    {
                        if (cfg.Verbose)
                            Console.WriteLine("Readconfig from config file");
                    }
                    if (string.IsNullOrEmpty(cfg.Output))
                        cfg.Output = expectCfg.Report.OutputFile;
                    if (string.IsNullOrEmpty(cfg.TemplateFile))
                        cfg.TemplateFile = expectCfg.Report.TemplateFile;
                    if (cfg.HeadingStyles == null || cfg.HeadingStyles.Length == 0)
                        cfg.HeadingStyles = expectCfg.Report.HeadingStyles.Split(';');
                    if (string.IsNullOrEmpty(cfg.SpecificationsStyle))
                        cfg.SpecificationsStyle = expectCfg.Report.Specifications;
                    if (string.IsNullOrEmpty(cfg.DescriptionsStyle))
                        cfg.DescriptionsStyle = expectCfg.Report.Descriptions;
                    if (string.IsNullOrEmpty(cfg.TablesStyle))
                        cfg.TablesStyle = expectCfg.Report.Tables;

                    foreach (ReportBlocElement reportBloc in expectCfg.Report.Blocs)
                    {
                        cfg.Blocs.Add(new TextBloc {StartToken = reportBloc.StartToken, EndToken = reportBloc.EndToken, StyleName = reportBloc.StyleName });
                    }

                    foreach (ReportTokenElement token in expectCfg.Report.Tokens)
                    {
                        cfg.Runs.Add(new TextRun
                            {
                                Token = token.Token, 
                                Bold = token.Bold, 
                                Underline = token.Underline, 
                                Italic = token.Italic
                            });
                    }
                }
            }

            return cfg;
        }

        private static Dictionary<string, string> ReadCustomProperties(string[] arguments)
        {
            var res = new Dictionary<string, string>();
            string lstStr = ReadArgument(arguments, "customproperties");
            if (!string.IsNullOrEmpty(lstStr))
            {
                var props = lstStr.Split(',');
                foreach (var prop in props)
                {
                    string[] elts = prop.Split(':');
                    if (elts.Length == 2)
                    {
                        res.Add(elts[0].Trim(), elts[1].Trim());
                    }
                }
            }
            return res;
        }

        private static string ReadArgument(string[] arguments, string argname)
        {
            string token = "-" + argname + "=";
            var arg = arguments.FirstOrDefault(s => s.StartsWith(token));
            if (arg == null) return null;
            arg = arg.Substring(token.Length);
            if (arg.StartsWith("\"") && arg.EndsWith("\""))
            {
                arg = arg.Substring(1, arg.Length - 2);
            }

            return arg;
        }

        private static string[] ReadArgumentList(string[] arguments, string argname)
        {
            var tmp = ReadArgument(arguments, argname);
            if (tmp != null)
            {
                return tmp.Split(new string[]{";"}, StringSplitOptions.RemoveEmptyEntries);
            }

            return null;
        }


        public bool ValidateForStyleList()
        {
            if (ParameterRequiredButNotFilled("template", TemplateFile)) return false;

            if (!File.Exists(TemplateFile))
            {
                Console.WriteLine("Template file " + TemplateFile + " not found");
                return false;
            }

            return true;
        }

        public bool Validate()
        {
            if (ParameterRequiredButNotFilled("source", Source)) return false;
            if (ParameterRequiredButNotFilled("output", Output)) return false;
            if (ParameterRequiredButNotFilled("template", TemplateFile)) return false;
            if (ParameterRequiredButNotFilled("headings", HeadingStyles)) return false;
            //if (ParameterRequiredButNotFilled("tables", TableStyles)) return false;

            if (!FileExists("source", Source)) return false;
            if (!FileExists("template", TemplateFile)) return false;

            return true;
        }

        private bool ParameterRequiredButNotFilled(string paramname, string paramval)
        {
            if (string.IsNullOrEmpty(paramval))
            {
                Console.WriteLine(paramname + " argument is required" + launchhelp);
                return true;
            }

            return false;
        }

        private bool ParameterRequiredButNotFilled(string paramname, string[] paramval)
        {
            if (paramval == null || paramval.Length == 0)
            {
                Console.WriteLine(paramname + " argument is required" + launchhelp);
                return true;
            }

            return false;
        }

        private bool FileExists(string paramname, string paramval)
        {
            if (!File.Exists(Source))
            {
                Console.WriteLine(paramname + " file \"" + Source + "\" not found");
                return false;
            }

            return true;
        }
    }
}
